package com.frank.oj.manager;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.frank.model.entity.contest.Contest;
import com.frank.oj.model.vo.ACMContestRankVO;
import com.frank.oj.model.vo.OIContestRankVO;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author frank
 * @Date 2024/4/19
 */
@Component
public class ContestRankManager {
    @Resource
    private ContestCalculateRankManager contestCalculateRankManager;

    public IPage getContestACMRankPage(boolean isOpenSealRank,
                                       Boolean removeStar,
                                       String currentUserId,
                                       List<String> concernedList,
                                       List<Integer> externalCidList,
                                       Contest contest,
                                       Integer currentPage,
                                       Integer limit,
                                       String keyword,
                                       boolean isContainsAfterContestJudge) {
        List<ACMContestRankVO> orderResultList = contestCalculateRankManager.calcACMRank(isOpenSealRank,
                removeStar,
                contest,
                currentUserId,
                concernedList,
                externalCidList,
                isContainsAfterContestJudge);

        if (StrUtil.isNotBlank(keyword)) {
            String finalKeyword = keyword.trim().toLowerCase();
            orderResultList = orderResultList.stream()
                    .filter(rankVO -> filterBySchoolORRankShowName(finalKeyword,
                            rankVO.getSchool(),
                            getUserRankShowName(contest.getRankShowName(),
                                    rankVO.getUsername(),
                                    rankVO.getRealname(),
                                    rankVO.getNickname()))).collect(Collectors.toList());
        }

        return getPagingRankList(orderResultList, currentPage, limit);
    }

    /**
     * 获取分页后的榜单
     *
     * @param rankList    全部数据
     * @param currentPage 当前页
     * @param limit       每页显示数量
     * @return 分页后的榜单
     */
    private <T> Page<T> getPagingRankList(List<T> rankList, int currentPage, int limit) {
        Page<T> page = new Page<>(currentPage, limit);
        int count = rankList.size();
        List<T> pageList = new ArrayList<>();
        int currId = currentPage > 1 ? (currentPage - 1) * limit : 0;
        for (int i = 0; i < limit && i < count - currId; i++) {
            pageList.add(rankList.get(currId + i));
        }
        page.setSize(limit);
        page.setCurrent(currentPage);
        page.setTotal(count);
        page.setRecords(pageList);
        return page;
    }

    private boolean filterBySchoolORRankShowName(String keyword, String school, String rankShowName) {
        if (StrUtil.isNotEmpty(school) && school.toLowerCase().contains(keyword)) {
            return true;
        }
        return StrUtil.isNotEmpty(rankShowName) && rankShowName.toLowerCase().contains(keyword);
    }

    private String getUserRankShowName(String contestRankShowName, String username, String realName, String nickname) {
        switch (contestRankShowName) {
            case "username":
                return username;
            case "realname":
                return realName;
            case "nickname":
                return nickname;
        }
        return null;
    }

    /**
     * 获取OI榜单
     *
     * @param isOpenSealRank              是否开启封榜
     * @param removeStar                  是否移除打星队伍
     * @param currentUserId               当前用户id
     * @param concernedList               关注的用户
     * @param externalCidList             外部比赛id
     * @param contest                     比赛实体
     * @param currentPage                 当前页
     * @param limit                       每页显示数量
     * @param keyword                     关键字
     * @param isContainsAfterContestJudge 是否包含赛后提交
     */
    public IPage getContestOIRankPage(boolean isOpenSealRank, Boolean removeStar, String currentUserId, List<String> concernedList, List<Integer> externalCidList, Contest contest, Integer currentPage, Integer limit, String keyword, boolean isContainsAfterContestJudge) {
        List<OIContestRankVO> orderResultList = contestCalculateRankManager.calcOIRank(isOpenSealRank,
                removeStar,
                contest,
                currentUserId,
                concernedList,
                externalCidList,
                isContainsAfterContestJudge);

        if (StrUtil.isNotBlank(keyword)) {
            String finalKeyword = keyword.trim().toLowerCase();
            orderResultList = orderResultList.stream()
                    .filter(rankVO -> filterBySchoolORRankShowName(finalKeyword,
                            rankVO.getSchool(),
                            getUserRankShowName(contest.getRankShowName(),
                                    rankVO.getUsername(),
                                    rankVO.getRealname(),
                                    rankVO.getNickname()))).collect(Collectors.toList());
        }
        return getPagingRankList(orderResultList, currentPage, limit);
    }

    public IPage getACMContestScoreboard(boolean isOpenSealRank, Boolean removeStar, Contest contest, String currentUserId, List<String> concernedList, List<Integer> externalCidList, Integer currentPage, Integer limit, String keyword, boolean useCache, long cacheTime, boolean isContainsAfterContestJudge) {

        if (CollectionUtils.isNotEmpty(externalCidList)) {
            useCache = false;
        }
        List<ACMContestRankVO> acmContestRankVOS = contestCalculateRankManager.calcACMRank(isOpenSealRank,
                removeStar,
                contest,
                currentUserId,
                concernedList,
                externalCidList,
                useCache,
                cacheTime,
                isContainsAfterContestJudge);

        if (StrUtil.isNotBlank(keyword)) {
            String finalKeyword = keyword.trim().toLowerCase();
            acmContestRankVOS = acmContestRankVOS.stream()
                    .filter(rankVo -> filterBySchoolORRankShowName(finalKeyword,
                            rankVo.getSchool(),
                            getUserRankShowName(contest.getRankShowName(),
                                    rankVo.getUsername(),
                                    rankVo.getRealname(),
                                    rankVo.getNickname())))
                    .collect(Collectors.toList());
        }
        return getPagingRankList(acmContestRankVOS, currentPage, limit);
    }

    public IPage getOIContestScoreboard(boolean isOpenSealRank, Boolean removeStar, Contest contest, String currentUserId, List<String> concernedList, List<Integer> externalCidList, Integer currentPage, Integer limit, String keyword, boolean useCache, long cacheTime, boolean isContainsAfterContestJudge) {

        if (CollectionUtil.isNotEmpty(externalCidList)) {
            useCache = false;
        }
        List<OIContestRankVO> oiContestRankVOList = contestCalculateRankManager.calcOIRank(isOpenSealRank,
                removeStar,
                contest,
                currentUserId,
                concernedList,
                externalCidList,
                useCache,
                cacheTime,
                isContainsAfterContestJudge);

        if (StrUtil.isNotBlank(keyword)) {
            String finalKeyword = keyword.trim().toLowerCase();
            oiContestRankVOList = oiContestRankVOList.stream()
                    .filter(rankVo -> filterBySchoolORRankShowName(finalKeyword,
                            rankVo.getSchool(),
                            getUserRankShowName(contest.getRankShowName(),
                                    rankVo.getUsername(),
                                    rankVo.getRealname(),
                                    rankVo.getNickname())))
                    .collect(Collectors.toList());
        }
        return getPagingRankList(oiContestRankVOList, currentPage, limit);
    }
}
